﻿using System;
using System.IO;
using System.Net;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Web;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Data.SqlClient;
using System.Collections;
using System.Xml;
using System.Reflection;
using System.Diagnostics;
using System.Threading;

namespace SlideShow
{
    public class DropboxApi
    {
        public OAuthToken _accessToken;
        public string _consumerKey;
        public string _consumerSecret;
        public ArrayList image_buffer = new ArrayList();//<image, filename> Image_item
        public ArrayList image_default = new ArrayList();
        private Object buffer_lock = new Object();
        private int count = 0;
        private string folderName;
        private int buffer_size=8;
        private ArrayList old_images = new ArrayList();//store path
        private ArrayList new_images = new ArrayList();//store path
        private int old_images_pointer = 0;
        private int current_count = 0;

        public DropboxApi(string consumerKey, string consumerSecret, OAuthToken accessToken)
        {
            _consumerKey = consumerKey;
            _consumerSecret = consumerSecret;
            _accessToken = accessToken;
            folderName = "Live";
        }
        public DropboxApi(string consumerKey, string consumerSecret) 
        {
            _consumerKey = consumerKey;
            _consumerSecret = consumerSecret;
            folderName = "Live";
        }

        public string GetResponse(Uri uri)
        {
            var oauth = new OAuth();
            var requestUri = oauth.SignRequest(uri, _consumerKey, _consumerSecret, _accessToken);
            var request = (HttpWebRequest) WebRequest.Create(requestUri);
            request.Method = WebRequestMethods.Http.Get;
            var response = request.GetResponse();
            var reader = new StreamReader(response.GetResponseStream());
            return reader.ReadToEnd();
        }

        public static T ParseJson<T>(string json) where T : class, new()
        {
            var jobject = JObject.Parse(json);
            return JsonConvert.DeserializeObject<T>(jobject.ToString());
        }

        public Account GetAccountInfo()
        {
            var uri = new Uri(new Uri(DropboxRestApi.BaseUri), "account/info");
            var json = GetResponse(uri);
            return ParseJson<Account>(json);
        }

        public File GetFiles(string root, string path)
        {
            var uri = new Uri(new Uri(DropboxRestApi.BaseUri), String.Format("metadata/{0}/{1}", root, path));
            var json = GetResponse(uri);
            return ParseJson<File>(json);
        }

        public FileSystemInfo CreateFolder(string root, string path)
        {
            var uri = new Uri(new Uri(DropboxRestApi.BaseUri),
                String.Format("fileops/create_folder?root={0}&path={1}", 
                root, UpperCaseUrlEncode(path)));
            var json = GetResponse(uri);
            return ParseJson<FileSystemInfo>(json);
        }

        public FileSystemInfo Move(string root, string fromPath, string toPath)
        {
            var uri = new Uri(new Uri(DropboxRestApi.BaseUri),
                String.Format("fileops/move?root={0}&from_path={1}&to_path={2}",
                root, UpperCaseUrlEncode(fromPath), UpperCaseUrlEncode(toPath)));
            var json = GetResponse(uri);
            return ParseJson<FileSystemInfo>(json);
        }

        public FileSystemInfo Delete(string root, string path)
        {
            var uri = new Uri(new Uri(DropboxRestApi.BaseUri),
                String.Format("fileops/delete?root={0}&path={1}", 
                root, UpperCaseUrlEncode(path)));
            var json = GetResponse(uri);
            return ParseJson<FileSystemInfo>(json);
        }

        public FileSystemInfo DownloadFile(string root, string path)
        {
            var uri = new Uri(new Uri(DropboxRestApi.ApiContentServer),
                String.Format("files?root={0}&path={1}",
                root, UpperCaseUrlEncode(path)));

            var oauth = new OAuth();
            var requestUri = oauth.SignRequest(uri, _consumerKey, _consumerSecret, _accessToken);

            var request = (HttpWebRequest)WebRequest.Create(requestUri);
            request.Method = WebRequestMethods.Http.Get;
            var response = request.GetResponse();

            var metadata = response.Headers["x-dropbox-metadata"];
            var file = ParseJson<FileSystemInfo>(metadata);

            using (Stream responseStream = response.GetResponseStream())
            using (MemoryStream memoryStream = new MemoryStream())
            {
                byte[] buffer = new byte[1024];
                int bytesRead;
                do
                {
                    bytesRead = responseStream.Read(buffer, 0, buffer.Length);
                    memoryStream.Write(buffer, 0, bytesRead);
                } while (bytesRead > 0);

                file.Data = memoryStream.ToArray();
            }

            return file;
        }

        public static string UpperCaseUrlEncode(string s)
        {
            char[] temp = HttpUtility.UrlEncode(s).ToCharArray();
            for (int i = 0; i < temp.Length - 2; i++)
            {
                if (temp[i] == '%')
                {
                    temp[i + 1] = char.ToUpper(temp[i + 1]);
                    temp[i + 2] = char.ToUpper(temp[i + 2]);
                }
            }
            return new string(temp);
        }

        public void dropbox_author()
        {
            var uri = new Uri("https://api.dropbox.com/1/oauth/request_token");

            OAuthBase oAuth = new OAuthBase();
            string nonce = oAuth.GenerateNonce();
            string timeStamp = oAuth.GenerateTimeStamp();
            string parameters;
            string normalizedUrl;
            string signature = oAuth.GenerateSignature(uri, _consumerKey, _consumerSecret, String.Empty, String.Empty, "GET", timeStamp, nonce,
                OAuthBase.SignatureTypes.HMACSHA1, out normalizedUrl, out parameters);
            signature = HttpUtility.UrlEncode(signature);

            StringBuilder requestUri = new StringBuilder(uri.ToString());
            requestUri.AppendFormat("?oauth_consumer_key={0}&", _consumerKey);
            requestUri.AppendFormat("oauth_nonce={0}&", nonce);
            requestUri.AppendFormat("oauth_timestamp={0}&", timeStamp);
            requestUri.AppendFormat("oauth_signature_method={0}&", "HMAC-SHA1");
            requestUri.AppendFormat("oauth_version={0}&", "1.0");
            requestUri.AppendFormat("oauth_signature={0}", signature);

            var request = (HttpWebRequest)WebRequest.Create(new Uri(requestUri.ToString()));
            request.Method = WebRequestMethods.Http.Get;

            var response = request.GetResponse();
            var queryString = new StreamReader(response.GetResponseStream()).ReadToEnd();
            var parts = queryString.Split('&');
            var token = parts[1].Substring(parts[1].IndexOf('=') + 1);
            var tokenSecret = parts[0].Substring(parts[0].IndexOf('=') + 1);

            var queryString1 = String.Format("oauth_token={0}", token);
            var authorizeUrl = "https://www.dropbox.com/1/oauth/authorize?" + queryString;
            Process.Start(authorizeUrl);
            System.Threading.Thread.Sleep(10000);
            dropbox_access(token, tokenSecret);
        }

        public void dropbox_access(string token, string tokenSecret)
        {
            var uri = "https://api.dropbox.com/1/oauth/access_token";

            OAuthBase oAuth = new OAuthBase();
            var nonce = oAuth.GenerateNonce();
            var timeStamp = oAuth.GenerateTimeStamp();
            string parameters;
            string normalizedUrl;
            var signature = oAuth.GenerateSignature(new Uri(uri), _consumerKey, _consumerSecret,
                token, tokenSecret, "GET", timeStamp, nonce,
                OAuthBase.SignatureTypes.HMACSHA1, out normalizedUrl, out parameters);

            signature = HttpUtility.UrlEncode(signature);
            var requestUri = new StringBuilder(uri);
            requestUri.AppendFormat("?oauth_consumer_key={0}&", _consumerKey);
            requestUri.AppendFormat("oauth_token={0}&", token);
            requestUri.AppendFormat("oauth_nonce={0}&", nonce);
            requestUri.AppendFormat("oauth_timestamp={0}&", timeStamp);
            requestUri.AppendFormat("oauth_signature_method={0}&", "HMAC-SHA1");
            requestUri.AppendFormat("oauth_version={0}&", "1.0");
            requestUri.AppendFormat("oauth_signature={0}", signature);

            var request = (HttpWebRequest)WebRequest.Create(requestUri.ToString());
            request.Method = WebRequestMethods.Http.Get;

            var response = request.GetResponse();
            var reader = new StreamReader(response.GetResponseStream());
            var accessToken = reader.ReadToEnd();

            var parts = accessToken.Split('&');
            var Token = parts[1].Substring(parts[1].IndexOf('=') + 1);
            var Secret = parts[0].Substring(parts[0].IndexOf('=') + 1);

            _accessToken = new OAuthToken(Token, Secret);


            //var api = new DropboxApi(consumerKey, consumerSecret, accessTokenObject);
            //var account = api.GetAccountInfo();
            //Console.WriteLine(Token);
            //Console.WriteLine(Secret);
            //Console.WriteLine(account);

            //var publicFolder = api.GetFiles("dropbox", "");
            //foreach (var file in publicFolder.Contents)
            //{
            //    Console.WriteLine(file.Path);
            //    Console.WriteLine(file.Modified);
            //    var files = api.DownloadFile("dropbox", file.Path);
            //    files.Save(@"C:\DropboxPart3.zip");

            //}
        }

        private Image ImageCropResize(Image image, int width, int height)
        {
            Bitmap bmpImage = new Bitmap(image);
            Image final_image = image;
            //crop
            //specify the crop area
            Rectangle cropArea = new Rectangle();
            cropArea.Width = image.Width;
            cropArea.Height = (int)(cropArea.Width * 9 / 16);
            int location_y = (int)(image.Height / 2 - cropArea.Height / 2);
            cropArea.Location = new Point(0, location_y);
            if (location_y < 0)
            {
                cropArea.Height = image.Height;
                cropArea.Width = (int)(cropArea.Height * 16 / 9);
                cropArea.Location = new Point((int)(image.Width / 2 - cropArea.Width / 2), 0);
            }
            //crop the image  get the bmpCrop
            Bitmap bmpCrop = bmpImage.Clone(cropArea, bmpImage.PixelFormat);
            //resize
            final_image = resizeImage((Image)bmpCrop, new Size(width, height));
            return final_image;
        }
        private Image resizeImage(Image imgToResize, Size size)
        {
            int sourceWidth = imgToResize.Width;
            int sourceHeight = imgToResize.Height;
            float nPercent = 0;
            float nPercentW = 0;
            float nPercentH = 0;
            nPercentW = ((float)size.Width / (float)sourceWidth);
            nPercentH = ((float)size.Height / (float)sourceHeight);

            if (nPercentH < nPercentW)
                nPercent = nPercentH;
            else
                nPercent = nPercentW;

            int destWidth = (int)(sourceWidth * nPercent);
            int destHeight = (int)(sourceHeight * nPercent);

            Bitmap bmpImage = new Bitmap(destWidth, destHeight);
            Graphics graphics = Graphics.FromImage((Image)bmpImage);
            graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;

            graphics.DrawImage(imgToResize, 0, 0, destWidth, destHeight);
            graphics.Dispose();

            return (Image)bmpImage;
        }

        public void initial()
        {
            
            dropbox_author();
            try
            {
                var liveFolder = GetFiles("dropbox", folderName);
                current_count = liveFolder.Contents.Count();
                Console.WriteLine("New files number= " + current_count);
                foreach (var file in liveFolder.Contents)//the order need to be test
                {
                    Console.WriteLine(file.Path);
                    //Console.WriteLine(file.Modified);
                    var files = DownloadFile("dropbox", file.Path);
                    //check if is image by minm_type
                    Image image_tmp = files.return_image();
                    image_buffer.Add(new Image_item((Image)ImageCropResize(image_tmp, 1280, 720), file.Path));
                    old_images.Add(file.Path);
                    //string[] filename = file.Path.Split('/');
                    count++;
                    if (count >= buffer_size)
                        break;
                }
                for (int i = image_buffer.Count; i < current_count; i++)
                {
                    new_images.Add(liveFolder.Contents.ElementAt(i).Path);
                }
                image_default = image_buffer;
            }
            catch(Exception e)
            {
                Console.WriteLine(e.Message);
            }
        }

        public void maintain()//maintian image buffer   a new thread   need test
        {
            lock (buffer_lock)
            {
                var liveFolder = GetFiles("dropbox", folderName);
                int dropbox_count = liveFolder.Contents.Count();
                for (int i = current_count; i < dropbox_count; i++)
                {
                    new_images.Add(liveFolder.Contents.ElementAt(i).Path);
                }
                int tmp_number = image_buffer.Count;
                //liveFolder.Contents.Count
                for (int i = 0; i < buffer_size - tmp_number; i++)//the order need to be test
                {
                    if (new_images.Count > 0)
                    {
                        int tmp_index = old_images.Count;//the first element in new_images will be the last element in the old_images
                        old_images.Add(old_images[0]);
                        new_images.RemoveAt(0);
                        var file = liveFolder.Contents.ElementAt(tmp_index);
                        //Console.WriteLine(file.Path);
                        //Console.WriteLine(file.Modified);
                        var files = DownloadFile("dropbox", file.Path);
                        //check if is image by minm_type
                        Image tmp_image = files.return_image();
                        image_buffer.Add(new Image_item((Image)ImageCropResize(tmp_image, 1280, 720), file.Path));
                        //string[] filename = file.Path.Split('/');
                    }
                    else
                    {
                        Console.WriteLine("liveFolder size = " +liveFolder.Contents.Count());
                        Console.WriteLine("old_images_pointer = " + old_images_pointer);
                        var file = liveFolder.Contents.ElementAt(old_images_pointer);

                        //Console.WriteLine(file.Path);
                        //Console.WriteLine(file.Modified);
                        var files = DownloadFile("dropbox", file.Path);
                        //check if is image by minm_type
                        Image tmp_image = files.return_image();
                        image_buffer.Add(new Image_item((Image)ImageCropResize(tmp_image, 1280, 720), file.Path));
                        //string[] filename = file.Path.Split('/');

                        old_images_pointer++;
                        if (old_images_pointer >= old_images.Count)
                            old_images_pointer = 0;
                    }
                }
                count += image_buffer.Count - tmp_number;
                Console.WriteLine("count = " + count);
            }
        }

        public ArrayList get_playlist(int number)
        {
            ArrayList playlist = new ArrayList();
            try
            {
                
                //firstly detect whether image_buffer is locked
                //if (number > image_buffer.Count)
                //    number = image_buffer.Count;
                int index = 0;
                for (int i = 0; i < number; i++)
                {
                    playlist.Add(image_buffer[index]);
                    index++;
                    if (index >= image_buffer.Count)
                        index = 0;
                }
                image_buffer.RemoveRange(0, number);
                Console.WriteLine("image_buffer size = " + image_buffer.Count);
                Thread t_maintain = new Thread(new ThreadStart(this.maintain));
                t_maintain.Start();
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
            return playlist;
        }

    }
}
